package com.example.software.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.ExpiredJwtException;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class JwtTokenUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    @Getter
    @Value("${jwt.tokenPrefix}")
    private String tokenPrefix;

    @Getter
    @Value("${jwt.headerName}")
    private String headerName;

    /**
     * 生成token
     * @param userId 用户ID
     * @param username 用户名
     * @param userType 用户类型
     * @return token
     */
    public String generateToken(Long userId, String username, String userType) {
        // 当前时间
        Date now = new Date();
        // 过期时间
        Date expirationDate = new Date(now.getTime() + expiration * 1000);
        
        log.debug("生成JWT Token - 用户ID: {}, 用户名: {}, 用户类型: {}", userId, username, userType);
        
        // 首先创建builder并设置标准字段
        return Jwts.builder()
                .setSubject(userId.toString())  // 显式设置subject
                .setIssuedAt(now)
                .setExpiration(expirationDate)
                .claim("username", username)  // 单独添加自定义字段
                .claim("userType", userType)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 解析token
     * @param token token
     * @return Claims
     */
    public Claims parseToken(String token) {
        try {
            // 更详细的日志记录，帮助诊断问题
            log.debug("开始解析token: {}", token.substring(0, Math.min(10, token.length())) + "...");
            
            Claims claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            
            // 记录解析后的主要信息（但不包含敏感数据）
            log.debug("Token解析成功 - Subject: {}, 过期时间: {}", 
                    claims.getSubject(),
                    claims.getExpiration());
                    
            // 检查token是否已过期
            Date expDate = claims.getExpiration();
            if (expDate != null && expDate.before(new Date())) {
                log.warn("Token已过期! 过期时间: {}, 当前时间: {}", expDate, new Date());
                throw new ExpiredJwtException(null, claims, "Token已过期，请重新登录");
            }
            
            return claims;
        } catch (ExpiredJwtException e) {
            log.error("Token已过期: {}", e.getMessage());
            throw e; // 重新抛出以便调用者正确处理
        } catch (Exception e) {
            log.error("解析token失败: {}", e.getMessage());
            throw new RuntimeException("无效的token: " + e.getMessage());
        }
    }

    /**
     * 从token中获取用户ID
     * @param token token
     * @return 用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = parseToken(token);
        Object userIdObj = claims.get("userId");
        if (userIdObj != null) {
            return Long.valueOf(userIdObj.toString());
        }
        // 向后兼容：尝试从subject获取
        String subject = claims.getSubject();
        if (subject != null) {
            return Long.valueOf(subject);
        }
        throw new RuntimeException("无法从token中获取用户ID");
    }

    /**
     * 从token中获取用户名
     * @param token token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = parseToken(token);
        Object usernameObj = claims.get("username");
        if (usernameObj != null) {
            return usernameObj.toString();
        }
        throw new RuntimeException("无法从token中获取用户名");
    }

    /**
     * 从token中获取用户类型
     * @param token token
     * @return 用户类型
     */
    public String getUserTypeFromToken(String token) {
        Claims claims = parseToken(token);
        Object userTypeObj = claims.get("userType");
        if (userTypeObj != null) {
            return userTypeObj.toString();
        }
        throw new RuntimeException("无法从token中获取用户类型");
    }

    /**
     * 验证token是否过期
     * @param token token
     * @return 是否过期
     */
    public boolean isTokenExpired(String token) {
        try {
            Claims claims = parseToken(token);
            Date expiration = claims.getExpiration();
            boolean isExpired = expiration.before(new Date());
            log.debug("Token过期检查 - 过期时间: {}, 当前时间: {}, 是否过期: {}", 
                    expiration, new Date(), isExpired);
            return isExpired;
        } catch (ExpiredJwtException e) {
            log.debug("Token已明确标记为过期");
            return true;
        } catch (Exception e) {
            log.warn("检查token过期时发生错误: {}", e.getMessage());
            return true;
        }
    }
} 